using System;
using System.Collections.Generic;
using System.Text;
using Noein.Control;
using Microsoft.DirectX;

namespace Noein.GeneticAlgorithm.New
{
    public class Problem
    {
        private class Output
        {
            public float averageSpeed = 0;
            // TODO add additional stats here

            public void Reset()
            {
                averageSpeed = 0;
            }
        }

        private List<Individual> solution;
        private List<Object> objects;
        private Output[] outputs;
        private int updateCount;
        
        public void SetSolution(List<Individual> solution)
        {
            this.solution = solution;
            outputs = new Output[solution.Count];
            for (int i = 0; i < solution.Count; i++)
            {
                outputs[i] = new Output();
            }

            updateCount = 0;

            // TODO implement support population resizing
            if (objects.Count != solution.Count)
                throw new Exception("Number of solution does not match problem requirement!");

            // associates GA solution with CA objects
            for (int j = 0; j < objects.Count; j++)
            {
                Object obj = objects[j];

                SpringMass sm = obj as SpringMass;

                if (sm != null)
                {
                    sm.scs = solution[j].Phenotype;
                }

                // remove old controller
                //int i = 0;
                //for (; i < obj.Controllers.Count; i++)
                //{
                //    if (obj.Controllers[i] as ScriptController != null)
                //    {
                //        obj.Controllers.RemoveAt(i);
                //        break;
                //    }
                //}

                //// add new controller
                //SpringMass sm = obj as SpringMass;
                //if (sm != null)
                //{
                //    sm.scs = solution[j].Phenotype;
                //}


                    

                // reset output
                //outputs[i].Reset();
            }
        }

        public Problem(List<Object> objects)
        {
            this.objects = objects;


        }

        public void UpdateOutput(float dt)
        {
            float f = updateCount == 0 ? 1 : updateCount;
            f /= ++updateCount;

            // update each solution's output
            for (int i = 0; i < outputs.Length; i++)
            {
                // update average speed
                outputs[i].averageSpeed *= f;
                float speed = 
                    (objects[i].Spatial.Position - objects[i].Spatial.PreviousPosition).Length() / dt;
                outputs[i].averageSpeed += speed / updateCount;
            }
        }

        public void UpdateFitness()
        {
            for (int i = 0; i < outputs.Length; i++)
            {
                solution[i].Fitness = outputs[i].averageSpeed;
            }
        }
    }
}
